/*
 * Copyright (c) 2006-2011 Christian Plattner. All rights reserved.
 * Please refer to the LICENSE.txt for licensing details.
 */
package ch.ethz.ssh2.packets;

import java.io.IOException;
import java.math.BigInteger;

import ch.ethz.ssh2.PacketFormatException;
import ch.ethz.ssh2.util.StringEncoder;

/**
 * @author Christian Plattner
 * @version $Id: TypesReader.java 153 2014-04-28 11:39:37Z dkocher@sudo.ch $
 */
public class TypesReader {
    byte[] arr;
    int pos = 0;
    int max = 0;

    public TypesReader(byte[] arr) {
        this.arr = arr;
        pos = 0;
        max = arr.length;
    }

    public TypesReader(byte[] arr, int off) {
        this.arr = arr;
        this.pos = off;
        this.max = arr.length;

        if((pos < 0) || (pos > arr.length)) {
            throw new IllegalArgumentException("Illegal offset.");
        }
    }

    public TypesReader(byte[] arr, int off, int len) {
        this.arr = arr;
        this.pos = off;
        this.max = off + len;

        if((pos < 0) || (pos > arr.length)) {
            throw new IllegalArgumentException("Illegal offset.");
        }

        if((max < 0) || (max > arr.length)) {
            throw new IllegalArgumentException("Illegal length.");
        }
    }

    public int readByte() throws IOException {
        if(pos >= max) {
            throw new PacketFormatException("Packet too short.");
        }

        return (arr[pos++] & 0xff);
    }

    public byte[] readBytes(int len) throws IOException {
        if((pos + len) > max) {
            throw new PacketFormatException("Packet too short.");
        }

        byte[] res = new byte[len];

        System.arraycopy(arr, pos, res, 0, len);
        pos += len;

        return res;
    }

    public void readBytes(byte[] dst, int off, int len) throws IOException {
        if((pos + len) > max) {
            throw new PacketFormatException("Packet too short.");
        }

        System.arraycopy(arr, pos, dst, off, len);
        pos += len;
    }

    public boolean readBoolean() throws IOException {
        if(pos >= max) {
            throw new PacketFormatException("Packet too short.");
        }

        return (arr[pos++] != 0);
    }

    public int readUINT32() throws IOException {
        if((pos + 4) > max) {
            throw new PacketFormatException("Packet too short.");
        }

        return ((arr[pos++] & 0xff) << 24) | ((arr[pos++] & 0xff) << 16) | ((arr[pos++] & 0xff) << 8)
                | (arr[pos++] & 0xff);
    }

    public long readUINT64() throws IOException {
        if((pos + 8) > max) {
            throw new PacketFormatException("Packet too short.");
        }

        long high = ((arr[pos++] & 0xff) << 24) | ((arr[pos++] & 0xff) << 16) | ((arr[pos++] & 0xff) << 8)
                | (arr[pos++] & 0xff); /* sign extension may take place - will be shifted away =) */

        long low = ((arr[pos++] & 0xff) << 24) | ((arr[pos++] & 0xff) << 16) | ((arr[pos++] & 0xff) << 8)
                | (arr[pos++] & 0xff); /* sign extension may take place - handle below */

        return (high << 32) | (low & 0xffffffffl); /* see Java language spec (15.22.1, 5.6.2) */
    }

    public BigInteger readMPINT() throws IOException {
        BigInteger b;

        byte raw[] = readByteString();

        if(raw.length == 0) {
            b = BigInteger.ZERO;
        }
        else {
            b = new BigInteger(raw);
        }

        return b;
    }

    public byte[] readByteString() throws IOException {
        int len = readUINT32();

        if((len + pos) > max) {
            throw new PacketFormatException("Malformed SSH byte string.");
        }

        byte[] res = new byte[len];
        System.arraycopy(arr, pos, res, 0, len);
        pos += len;
        return res;
    }

    public String readString(String charsetName) throws IOException {
        int len = readUINT32();

        if((len + pos) > max) {
            throw new PacketFormatException("Malformed SSH string.");
        }

        String res = (charsetName == null) ? new String(arr, pos, len) : new String(arr, pos, len, charsetName);
        pos += len;

        return res;
    }

    public String readString() throws IOException {
        int len = readUINT32();

        if((len + pos) > max) {
            throw new PacketFormatException("Malformed SSH string.");
        }

        String res = StringEncoder.GetString(arr, pos, len);
        pos += len;

        return res;
    }

    public String[] readNameList() throws IOException {
        return readString().split(",");
    }

    public int remain() {
        return max - pos;
    }

}
